﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Maestro_Proveedores.clases.almacen
{
    class SuavExpSimple : ModeloAbstracto
    {

        
        private double alfaOptimo;
        ArrayList resultadosN;

        //-------------------------CONSTRUCTOR DE CLASE

        public SuavExpSimple()
        {
            this.nombreModelo = "Suavizacion Exponencial Simple";
            this.resultadosN = new System.Collections.ArrayList();
            resNideal = new Resultado();
        }

        //------------------------ INICIO METODOS SOBREESCRITOS

        public override Resultado obtenerResultado()
        {
            return this.resNideal;
        }

        public override void pronosticoSemanaN()
        {
            // se realiza una copia de la lista original, para cada calculo de N
            System.Collections.ArrayList registrosClon = new System.Collections.ArrayList();
            registrosClon = copiarArrayList(registros);
            semanaPronostico = registros.Count;
            Registro regAnterior = (Registro)registrosClon[semanaPronostico - 1];
            resNideal.pronosticoN1 = alfaOptimo * regAnterior.Demanda + (1 - alfaOptimo) * regAnterior.Pronostico;
        }

        public override void calcularModelo(System.Collections.ArrayList registrosF)
        {
            this.registros = registrosF;
            // se evalua que existan mas de 52 datos de pronostico..
            if (registros.Count >= 53)
            {
                // calculo del promedio de las primeras 45 semanas, para el pronostico de la semana 45
                double promedio44 = promediosem(44);

                Registro reg45 = new Registro();
                // se asigna el pronostico para la semana 53
                foreach (Registro reg in registros) 
                {
                    if (reg.Semana == 45)
                    {
                        reg.Pronostico = promedio44;
                        //se calcula el et
                        reg.Et = reg.Demanda - reg.Pronostico;
                        //se calcula el etabsoluto
                        reg.Etabsoluto = Math.Abs(reg.Et);
                        //se calcula el etcuadrado
                        reg.Etcuadrado = Math.Pow(reg.Et, 2);
                        //se calcula el APE
                        reg.Ape = 100 * (Math.Abs(reg.Et / reg.Demanda));
                        //se calcula el APE1
                        reg.Ape1 = 100 * (Math.Abs(reg.Et / reg.Pronostico));
                        reg45 = reg;
                        break;
                    }
                }

                ////calculo de la primera corrida
                //ArrayList pronosticoInicial = pronosticoParcial(reg46, alfaInicio, registros);
                //registros = pronosticoInicial;

                ////calculan los resultados ET, ETabsoluto, Etcuadrado
                //resNideal = calcularResultados(pronosticoInicial);

                //Corrida para encontrar el alfa optimo

                for (double a = 0.001; a < 1; a = a + 0.001)
                {
                    ////calculo de la primera corrida
                    ArrayList pronosticoInicial = pronosticoParcial(reg45, a, registros);
                    ////calculan los resultados ET, ETabsoluto, Etcuadrado
                    Resultado resultadoParcial = new Resultado();
                    resultadoParcial = calcularResultados(pronosticoInicial);
                    resultadoParcial.AlfaOptimo = a;
                    this.resultadosN.Add(resultadoParcial);
                }

                this.resNideal = CalcAlfaOptimo(resultadosN);

                //se asigna el alfa optimo
                this.alfaOptimo = resNideal.AlfaOptimo;

                //Pronostico con el alfa ideal
                ArrayList pronosticoFinal = pronosticoParcial(reg45, alfaOptimo, registros);
                registros = pronosticoFinal;
                //calculan los resultados ET, ETabsoluto, Etcuadrado
                resNideal = calcularResultados(pronosticoFinal);
                resNideal.RegistrosFinal = pronosticoFinal;
                // se calcula el pronostico para la siguiente semana (N+1) se al macena en el resNIDEal
                pronosticoSemanaN();
                //this.mostrarArreglo("SuavExpsimple-ALfa-"+alfaOptimo);
            }
            else
            {
                // el archivo no tiene minimo 53 semanas
                System.Windows.Forms.MessageBox.Show("Debe cargar minimo 53 Semanas");
            }
        }


        //------------------------ FIN METODOS SOBREESCRITOS


        private Resultado calcularResultados(ArrayList registros)
        {
            Resultado resultado = new Resultado();

            double sumatoriaMAD = 0;
            double sumatoriaECM = 0;
            double sumatoriaMAPE = 0;
            double sumatoriaMAPE1 = 0;
            double count = 0;

            foreach (Registro reg in registros)
            {
                if (reg.Pronostico != 0)
                {
                    sumatoriaMAD += reg.Etabsoluto;
                    sumatoriaECM += reg.Etcuadrado;
                    sumatoriaMAPE += reg.Ape;
                    sumatoriaMAPE1 += reg.Ape1;
                    count++;
                }
            }

            resultado.ECM = sumatoriaECM / count;
            resultado.MAD = sumatoriaMAD / count;
            resultado.MAPE = sumatoriaMAPE / count;
            resultado.MAPE1 = sumatoriaMAPE1 / count;

            return resultado;
        }

        private ArrayList pronosticoParcial(Registro reg45, double alfa, ArrayList registros)
        {
            // se realiza una copia de la lista original, para cada calculo de N
            ArrayList registrosClon = new System.Collections.ArrayList();
            registrosClon = copiarArrayList(registros);

            Registro regAnterior = reg45;
            foreach (Registro reg in registrosClon)
            {
                if (reg.Semana > 45)
                {
                    // calculo del pronostico
                    reg.Pronostico = alfa * regAnterior.Demanda + (1 - alfa) * regAnterior.Pronostico;
                    //se calcula el et
                    reg.Et = reg.Demanda - reg.Pronostico;
                    //se calcula el etabsoluto
                    reg.Etabsoluto = Math.Abs(reg.Et);
                    //se calcula el etcuadrado
                    reg.Etcuadrado = Math.Pow(reg.Et, 2);
                    //se calcula el APE
                    reg.Ape = 100 * (Math.Abs(reg.Et / reg.Demanda));
                    //se calcula el APE1
                    reg.Ape1 = 100 * (Math.Abs(reg.Et / reg.Pronostico));

                    //se actualiza el registro anterior para el proximo pronostico
                    regAnterior = reg;
                }
            }

            return registrosClon;
        }


        // funcion para calcular el promedio de la semana n
        private double promediosem(int semana)
        {
            double sum = 0;
            double prom = 0;
            foreach (Registro reg in registros)
            {
                if (reg.Semana <= semana)
                {
                    sum += reg.Demanda;
                }
            }
            prom = sum / semana;
            return prom;
        }


        public void  mostrarArreglo(String nombre)
        {
            //Gestion_Inventario_Proveedores.clases.herramientas.FileManager file = new Gestion_Inventario_Proveedores.clases.herramientas.FileManager();
            //file.generarArchivo(registros,nombre);
        }


    }
}
